/*
 * PacketDispatcher.cpp
 *
 *  Created on: Apr 17, 2017
 *      Author: zhangjf
 */

#include <Poco/Task.h>
#include <Poco/Util/Application.h>
#include <Poco/Delegate.h>
#include <Poco/JSON/Parser.h>
#include <Poco/JSON/Object.h>
#include <Poco/ErrorHandler.h>

using namespace Poco;
using namespace Poco::Util;
using namespace Poco::JSON;

#include "Helper.h"
#include "NetworkSubsystem.h"
#include "CustomNotification.h"
#include "Packet.h"
#include "PacketParams.h"
#include "JsonrpcInterface.h"
#include "PacketDispatcher.h"

namespace network
{

PacketDispatcher::PacketDispatcher(NotificationQueue& nq)
: Task("PacketDispatcher")
, _nq(nq)
{
	// TODO Auto-generated constructor stub

}

PacketDispatcher::~PacketDispatcher()
{
	// TODO Auto-generated destructor stub
}

void PacketDispatcher::runTask()
{
	JsonrpcProcessor processor;
	bool blNotif;
	Object joResp;
	Parser parser;

	processor.doCheckParams += delegate(this, &PacketDispatcher::onCheckParams);
	processor.doRunJsonrpcMethod += delegate(this, &PacketDispatcher::onRunJsonrpcMethod);
	while (!isCancelled())
	{
		CustomNotification<PacketParams> *pNotif = dynamic_cast<CustomNotification<PacketParams>*>(_nq.waitDequeueNotification());
		if (pNotif)
		{
			//poco_information(NetworkSubsystem::instance().logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + ": "
					//+ "handle CustomNotification<PacketParams> notification : ");
			const Packet::Ptr& packet = pNotif->custom().getPacket();

			//poco_information(NetworkSubsystem::instance().logger(), std::string("packet type: ") + std::to_string(packet->getHeader()->type));
			if (packet->getHeader()->type == MSG_TYPE::MSG_TYPE_JSONRPC)
			{
				//poco_information(NetworkSubsystem::instance().logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + ": "
						//+ "handle jsonrpc notification");
				joResp.clear();
				std::string strJsonReq = packet->getDataString();

				try
				{
					processor.process(strJsonReq, joResp, blNotif);
				}
				catch (JSONException& exc)
				{
					poco_information(NetworkSubsystem::instance().logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + ": "
							+ exc.displayText());
				}
				catch (SyntaxException& exc)
				{
					poco_information(NetworkSubsystem::instance().logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + ": "
							+ exc.displayText());
				}
				catch(...)
				{
					ErrorHandler::handle();
				}

				poco_information(NetworkSubsystem::instance().logger(), "blNotif = " + std::to_string(blNotif));
				if (!blNotif)
				{
					ostringstream oss;
					joResp.stringify(oss);
					std::string strResp = oss.str();
					poco_information(NetworkSubsystem::instance().logger(), "send response: " + strResp);

					PacketHeader header;
					header.type = MSG_TYPE::MSG_TYPE_JSONRPC;
					header.length = strResp.length() + 1 + sizeof(header);
					pNotif->custom().getSocket().sendBytes(&header, sizeof(header));
					pNotif->custom().getSocket().sendBytes(strResp.c_str(), strResp.length() + 1);
					poco_information(NetworkSubsystem::instance().logger(), "response success");
				}

				pNotif->release();
			}
			else
			{
				poco_information(NetworkSubsystem::instance().logger(), std::string(__func__) + ", " + std::to_string(__LINE__) + ": "
						+ "unhandled message");
			}
		}
	}
	processor.doCheckParams -= delegate(this, &PacketDispatcher::onCheckParams);
	processor.doRunJsonrpcMethod -= delegate(this, &PacketDispatcher::onRunJsonrpcMethod);
}

void PacketDispatcher::onCheckParams(const void* pSender, JsonrpcParams& params)
{
	poco_information(NetworkSubsystem::instance().logger(), "blNotif = " + std::to_string(params.blNotif));
	params.blRet = true;
}

void PacketDispatcher::onRunJsonrpcMethod(const void* pSender, JsonrpcParams& params)
{
	JsonrpcInterface::Ptr interface = JsonrpcInterfaceFactory::createInterface(params.strMethod, params.joParams);

	if (interface->process() == true)
	{
		params.joResult = interface->getResult();
		params.blRet = true;
	}
	else
	{
		params.joResult = interface->getError();
		params.blRet = false;
	}

	//poco_information(NetworkSubsystem::instance().logger(), "joResp: " + ((DynamicStruct)params.joResult).toString());
}

} /* namespace network */
